from typing import Dict, Any, Type

from strategy import FixedMoneyBuySeller, SingleMaStg, DoubleMaStg
from strategy.core.Stg import Stg
from strategy.handler.BuySeller import BuySeller
from strategy.stg.DownLimit import DownLimit
from strategy.stg.UpLimit import UpLimit
from tools import *


class Manager:
    stgs: Dict[str, Type[Stg]] = {}
    BuySeller: Type[BuySeller] = FixedMoneyBuySeller
    testStartDate = None
    testEndDate = None
    codes = []

    def addStg(self, stg):
        """加载策略和参数"""
        stgName = stg.__name__
        self.stgs[stgName] = stg

    def getStgsName(self):
        return ".".join(self.stgs.keys())

    def clearOldDate(self):
        for stgName, stgCls in self.stgs.items():
            dbTool.query(f"delete from my_signals where stg='{stgName}'")
            dbTool.query(f"delete from my_result where stg='{stgName}'")
        dbTool.query(f"delete from my_result where stg='{self.getStgsName()}'")

    def singleSignalTest(self):  # 单信号测试
        self.clearOldDate()
        pos = 0
        all = len(self.codes)
        for code in self.codes:  # 遍历股票
            pos += 1
            tool.log("\n开始测试: %s, %d/%d" % (code, pos, all))
            tool.code = code
            data = dataTool.getKdata(code, startDate=self.testStartDate, endDate=self.testEndDate)
            if len(data) == 0:
                continue
            # 生成信号
            for stgName, stgCls in self.stgs.items():  # 遍历策略, 分别计算策略信号, 后续可以任意组合信号
                stgObj = stgCls()
                stgObj.code = code
                stgObj.data = data
                params = stgObj.getParams()
                for param in params:  # 遍历参数
                    stgObj.param = param
                    # 获取uuid
                    uuid = tool.getUUID()
                    signals = stgObj.run(uuid)
                    # 执行交易
                    if len(signals) != 0:
                        buySeller = self.BuySeller()
                        buySeller.config(code, uuid, stgObj.getStgName(), signals, data)
                        buySeller.execute()

    def mergeSignalTest(self):  # 合并信号测试
        self.clearOldDate()
        pos = 0
        all = len(self.codes)
        for code in self.codes:  # 遍历股票
            pos += 1
            tool.log("\n开始测试: %s, %d/%d" % (code, pos, all))
            tool.code = code
            data = dataTool.getKdata(code, startDate=self.testStartDate, endDate=self.testEndDate)
            if len(data) == 0:
                continue
            # 生成信号
            allSignals = []
            uuid = tool.getUUID()
            for stgName, stgCls in self.stgs.items():  # 遍历策略, 分别计算策略信号, 后续可以任意组合信号
                stgObj = stgCls()
                stgObj.code = code
                stgObj.data = data
                # 组合策略使用默认参数, 也就是param原有的值
                signals = stgObj.run(uuid)
                allSignals.append(signals)
            # 合并信号
            mergeSignals = []
            for signals in allSignals:
                for date, signal in signals.items():
                    if date not in mergeSignals:
                        mergeSignals[date] = signal
                    else:
                        mergeSignals[date] += signal
            # 执行交易
            if len(mergeSignals) != 0:
                buySeller = self.BuySeller()
                buySeller.config(code, uuid, self.getStgsName(), mergeSignals, data)
                buySeller.execute()

    def customTest(self):
        # 时间: 20181228, 代码: 000034.SZ, 总输入: 450.0, 总输出: 2038.0, 盈利率: 3.53 参数: {"fastPeriod": 65, "slowPeriod": 170}
        # code = '000005.SZ'  # 亏,股票没价值
        code = '002549.SZ'
        # stgCls = DoubleMaStg
        config.logLevel = constant.logLevel_trade
        data = dataTool.getKdata(code, startDate='20180101', endDate='20200101')
        stg = DoubleMaStg()
        stg.param = {'fastPeriod': 12, 'slowPeriod': 26, 'signalPeriod': 9}
        stg.code = code
        stg.data = data
        uuid = tool.getUUID()
        signals = stg.run(uuid)
        buySeller = self.BuySeller()
        buySeller.config(code, 1, stg.getStgName(), signals, data)
        buySeller.execute()


if __name__ == '__main__':
    manager = Manager()
    # 配置
    manager.testStartDate = '20180101'
    manager.testEndDate = '20200101'
    manager.BuySeller = FixedMoneyBuySeller
    # manager.codes = dataTool.getCalcTradeCode(manager.testStartDate, manager.testEndDate)
    manager.codes = dataTool.getCodes()
    # manager.addStg(SingleMaStg)
    # manager.addStg(DownLimit)
    manager.addStg(UpLimit)
    # 运行
    manager.singleSignalTest()
